Title Banner

Previous Book Contents Book Index Next

Inside Macintosh: OpenDoc Programmer's Guide / Part 2 - Programming
Chapter 5 - User Events


About Event Handling in OpenDoc

Your OpenDoc part editor is required to respond to a specific set of actions or messages from OpenDoc that, although generated and passed in different ways on different platforms, constitute the majority of user interactions with your parts. In OpenDoc, these messages are called user events.

User events in OpenDoc include mouse clicks and keystrokes, menu commands, activation and deactivation of windows, and other events available only on some platforms. This section defines the different types of events and discusses how your part editor's HandleEvent method handles them.

How User Events Are Handled

The document shell receives platform-specific events through whatever event-
delivery mechanism the underlying platform provides. The shell converts them into the form of OpenDoc user events and passes them to the dispatcher by calling its Dispatch method. The dispatcher handles the events it recognizes, using a dispatch module to pass events to individual parts. The Dispatch method returns all other events, as well as events passed to parts but not handled by them, to the document shell to handle.

When the OpenDoc dispatcher receives an event intended for your part, it locates a dispatch module for the event. The dispatch module in turn calls your part's HandleEvent method. (Your part's Draw method can be called indirectly because of an event, through the Update method of a window or facet.)

Your part becomes the target for a specific type of user event (other than geometry-based events) by obtaining the focus for that event. The OpenDoc arbitrator keeps track of which part owns which foci by consulting a focus module, which tracks, for example, which part is currently active and therefore should receive keystroke events. Foci and focus modules are described further in the section "Focus Types".

Geometry-based events, such as mouse clicks, are generally dispatched to the parts within whose frames they occur, regardless of which part currently has the selection focus--that is, regardless of which part is currently active. This permits inside-out activation to occur.

Your part receives some of the information about its events in a platform-specific event structure. On the Mac OS platform, the event structure is equivalent to an event record. This is its definition:

struct ODEventData {
   short what;
   long  message;
   long  when;
   Point where;
   short modifiers;
};
Other information about the event is passed to your part (on the Mac OS platform) in an OpenDoc-defined event-info structure:

struct ODEventInfo
{
   ODFrame embeddedFrame;
   ODFacet embeddedFacet;
   ODPoint where;
   ODBoolean propagated;
};
For any geometry-based event (mouse event) that is passed to your part, the coordinates of the event are passed in the where field of the structure. For events in embedded frames that are passed to your part, the frame and facet within which the event occurred are passed in the embeddedFrame and embeddedFacet fields.

Types of User Events

On the Mac OS platform, your parts must in general handle the types of user events listed in Table 5-1. Not all of these events exist on all other platforms.
Table 5-1 OpenDoc user events (Mac OS platform)
Standard Mac OS eventsOpenDoc-defined events
kODEvtNullkODEvtMenu
kODEvtMouseDownkODEvtWindow
kODEvtMouseUpkODEvtMouseEnter
kODEvtKeyDownkODEvtMouseWithin
kODEvtKeyUpkODEvtMouseLeave
kODEvtAutoKeykODEvtBGMouseDown
kODEvtUpdatekODEvtMouseDownBorder[4]
kODEvtActivatekODEvtMouseDownEmbedded[4]
kODEvtOSkODEvtMouseUpEmbedded[4]
 kODEvtBGMouseDownEmbedded[4]

The following sections describe how you handle each of these kinds of events.

Mouse Events

When the user presses or releases the mouse button while the mouse pointer is in the content area of an OpenDoc window, the dispatcher finds the correct part to handle the mouse event by traversing the hierarchy of facets in the window.

The dispatcher searches depth-first (trying the most deeply embedded facets first) and front-to-back (trying the frontmost of sibling facets first). The dispatcher sends the event to the editor of the first--that is, most deeply embedded and frontmost--frame it finds whose active shape contains the pointer position. In this way the smallest enclosing frame surrounding the pointer location receives the mouse event, preserving the OpenDoc inside-out activation model. None of the part editors of any containing parts in that frame's embedding hierarchy are involved in handling the event.

When the user presses a mouse button while the pointer is within a facet of your part, the dispatcher calls your part's HandleEvent method, passing it an event type of kODEvtMouseDown. (If your part is in a document in a background process on the Mac OS, the dispatcher passes your HandleEvent method an event type of kODEvtBGMouseDown.)

When the user releases the mouse button while the pointer is within your facet, the dispatcher again calls your part's HandleEvent method, this time passing it an event type of kODEvtMouseUp.

The event-dispatching code does not itself activate and deactivate the relevant parts; it is up to the editor of the part receiving the mouse event to decide whether to activate itself or not. See the section "Mouse Events, Activation, and Dragging" for information on how your part should handle mouse-down and mouse-up events within its facets for the purposes of part activation, window activation, and drag and drop.

The dispatcher also tracks pointer position at all times when the mouse button is not pressed.

You can use these events to, for example, change the cursor appearance. See "Mouse-Up Tracking".

In some situations in the Mac OS platform, OpenDoc redirects or changes mouse events:

Mouse clicks within controls associated with your part can be handled in a number of ways, as discussed in the section "Controls".

Mouse Events in Embedded Frames

If your part contains embedded frames, the dispatcher can also send you special mouse events that occur within and on the borders of the embedded frames' facets.

The following events occur when your part's frame is the active frame and the embedded frame is selected or bundled or in icon view type, or if the user Shift-clicks or Command-clicks in the embedded frame to extend a selection:

The following event occurs when the frame embedded within your part is the active frame:

These events allow your part to activate itself and select or drag the embedded part.

Keystroke Events

When the user presses a key on the keyboard and your part has the keystroke focus, the dispatcher calls your part's HandleEvent method, passing it an event type of kODEvtKeyDown. When the user releases the key, the dispatcher again calls your part's HandleEvent method, this time passing it an event type of kODEvtKeyUp.

Exceptions to this convention include keystroke events that are keyboard equivalents to menu commands, which go to your part as menu events, and keystroke events involving the Page Up, Page Down, Home, and End keys, which go to the frame--if any--that has the scrolling focus.

Menu Events

If the user presses the mouse button when the pointer is within the menu bar, or if the user enters a keyboard equivalent to that action, OpenDoc converts the mouse-down or keystroke event into a menu event of type kODEvtMenu and calls the HandleEvent method of the part with the menu focus.

On the Mac OS platform, the message field of the event structure passed to HandleEvent specifies the menu and item selected, equivalent to the results of calling the MenuSelect or MenuKey function of the Menu Manager. In addition, the HandleEvent method can obtain a command ID for the menu event by calling the GetCommand method of the menu bar object.

Handling individual menu commands is discussed in the section "Menus"

Window Events

If the user presses the mouse button while the pointer is within a noncontent portion of the window (such as the close box in the title bar of a Mac OS window), or if the user enters a keyboard equivalent to that action, OpenDoc converts the mouse-down or keystroke event into an event of type kODEvtWindow and calls the HandleEvent method of the window's root part.

If the root part does not handle the event, the dispatcher returns it to the document shell, which performs the intended action (such as closing the window). However, if your part is the root part it can handle the event if it wishes. For example, it might hide the window rather than closing it.

For window events, the message field of the event structure contains the part code--equivalent to the results of the Mac OS FindWindow function--describing the part of the window, such as the close box, in which the event occurred.

How to handle window events when your part is the root part is described in the section "Handling Window Events".

Activate Events

On platforms such as Mac OS that support activation and deactivation of windows, OpenDoc sends activate events and deactivate events, of type kODEvtActivate, to each facet in the window when the window changes state.

If the user clicks in the title bar of an inactive Mac OS window, OpenDoc activates the window and brings it to the front. If the user clicks in the content area of an inactive window, the part at the click location brings the window to the front. Either way, when an active Mac OS window becomes inactive because another Mac OS window has become active, each facet of each part displayed in the window being deactivated receives a deactivate event, and each facet of each part displayed in the window being activated receives an activate event.

Your part's HandleEvent method can use these events to store and retrieve information that allows your part to decide whether or not to activate itself when its window becomes active. See "Handling Activate Events" for an explanation.

Update Events

To support redrawing of previously invalidated areas of a window, frame, or facet, OpenDoc handles update events and calls the Draw methods of the appropriate parts.

Update events are themselves triggered by the existence of invalid areas, created through changes to the content of parts, the activation of windows, or the removal of obscuring objects such as floating windows.

OpenDoc does not pass update events to your HandleEvent method. When an update event occurs that involves a facet of your part, the dispatcher calls the Update method of the window, which results in a call to your Draw method. For more information, see the section "Invalidating and Updating".

Null Events

On platforms such as the Mac OS that support the concept of idle time, OpenDoc permits your part to receive idle-time events, also called null events (type kODEvtNull). To receive null events, your part must first call the RegisterIdle method of the dispatcher to register each frame that is to receive null events. When you call RegisterIdle, you specify an idle frequency. OpenDoc uses the idle frequency to compute the sleep time it passes to WaitNextEvent.

Your call to the RegisterIdle method might occur in your part's DisplayFrameAdded, DisplayFrameConnected, or FacetAdded methods. You should unregister any idle frames (using the dispatcher's UnregisterIdle method) before the frames are deleted. You might make the call in your
part's DisplayFrameClosed and DisplayFrameRemoved methods.

Other Events

Other Mac OS-specific events are handled in these ways:

Propagating Events

A containing part can set a flag in an embedded frame that allows the containing part to receive events not handled by the embedded frame. If your part contains embedded frames with that flag set, your HandleEvent method receives the events originally sent to them. OpenDoc sets the propagated field in the eventInfo structure (see page 189) to true when passing a propagated event to your part.

Whenever you add a facet to a frame, you can check the state of the flag by calling the frame's DoesPropagateEvents method. You can then set or clear the flag by calling the frame's SetPropagateEvents method.

This is a specialized feature of OpenDoc, not likely to be used by most part editors. You might use it to manipulate embedded selections; for example, you could use tab-key events to allow the user to tab between embedded parts that do not themselves support tabbing or otherwise handle tab-key events.

If you do not set the event-propagating flag for any of your embedded frames, your HandleEvent method receives only those embedded-frame events described under "Mouse Events in Embedded Frames"

The HandleEvent Method of Your Part Editor

The dispatcher calls your part's HandleEvent method to pass it a user event meant for your part. This is the method's interface:

ODBoolean HandleEvent(inout ODEventData event, 
                      in ODFrame frame, 
                      in ODFacet facet),
                      inout ODEventInfo eventInfo);
Your implementation of HandleEvent might be similar to this:

  1. Set the result flag to kODFalse.
  2. Obtain the part info data from the frame or facet to which the event was directed, if you have stored relevant information there.
  3. Execute a switch statement with one case for each event type. Pass execution to the appropriate handler for each event type. Set the result flag to kODTrue if an individual handler handles the event.
  4. Return the result flag as the method result.

Your individual event handlers should function as described in other sections of this chapter. Each should return kODTrue to HandleEvent if it handles an event, and kODFalse if it does not.


[4] Container parts (parts that can embed other parts) must handle these events.

Previous Book Contents Book Index Next

© Apple Computer, Inc.
16 JUL 1996




Navigation graphic, see text links

Main | Page One | What's New | Apple Computer, Inc. | Find It | Contact Us | Help